name: CI/CD

on:
  workflow_dispatch:
  push:
    branches:
      - "main"
    tags:
      - "v*"
  merge_group:
  pull_request:
    branches:
      - "main"

defaults:
  run:
    working-directory: web

jobs:
  lint:
    defaults:
      run:
        working-directory: .
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 20
          cache: "npm"
          cache-dependency-path: "**/package-lock.json"
      - name: install dependencies
        run: |
          npm ci
      - name: Load default env
        run: |
          cp .env.dev.example .env
      - name: lint web
        working-directory: ./web
        run: npm run lint
      - name: lint worker
        working-directory: ./worker
        run: npm run lint

  test-docker-build:
    defaults:
      run:
        working-directory: web
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Build Web Docker image
        uses: docker/build-push-action@v4
        with:
          context: web
          push: false

      - name: Build Worker Docker image
        uses: docker/build-push-action@v4
        with:
          context: worker
          push: false

  tests:
    defaults:
      run:
        working-directory: web
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20]
    steps:
      - name: Set Swap Space
        uses: pierotofy/set-swap-space@master
        with:
          swap-size-gb: 10

      - uses: actions/checkout@v3
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
          cache: "npm"
          cache-dependency-path: "**/package-lock.json"

      - name: install dependencies
        run: |
          npm ci

      - name: Load default env
        working-directory: .
        run: |
          cp .env.dev.example .env
          cp .env.dev.example web/.env

      - name: Run + migrate
        working-directory: .
        run: |
          docker-compose -f docker-compose.dev.yml up -d
          sleep 5 # Wait for PostgreSQL to accept connections

      - name: Seed DB
        run: |
          npx --yes prisma migrate reset --force --skip-generate

      - name: Build
        run: npm run build

      - name: Start Langfuse
        run: (npm start&)

      - name: run tests
        run: npm run test

  e2e-tests:
    defaults:
      run:
        working-directory: web
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 20
          cache: "npm"
          cache-dependency-path: "**/package-lock.json"

      - name: install dependencies
        run: |
          npm ci

      - name: Load default env
        working-directory: .
        run: |
          cp .env.dev.example .env
          cp .env.dev.example web/.env

      - name: Run + migrate
        working-directory: .
        run: |
          docker-compose -f docker-compose.dev.yml up -d
          sleep 5 # Wait for PostgreSQL to accept connections

      - name: Seed DB
        run: |
          npx --yes prisma migrate reset --force --skip-generate

      - name: Build
        run: npm run build

      - name: Install playwright
        run: npx playwright install

      - name: Run e2e tests
        run: npm run test:e2e

  all-ci-passed:
    # This allows us to have a branch protection rule for tests and deploys with matrix
    runs-on: ubuntu-latest
    needs: [lint, tests, e2e-tests, test-docker-build]
    if: always()
    steps:
      - name: Successful deploy
        if: ${{ !(contains(needs.*.result, 'failure')) }}
        run: exit 0
        working-directory: .
      - name: Failing deploy
        if: ${{ contains(needs.*.result, 'failure') }}
        run: exit 1
        working-directory: .

  push-docker-image:
    needs: all-ci-passed
    if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/'))
    environment: "protected branches"
    runs-on: ubuntu-latest
    env:
      REGISTRY: ghcr.io
      IMAGE_NAME: ${{ github.repository }}
    permissions:
      packages: write
      contents: read

    steps:
      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: 20
          cache-dependency-path: "**/package-lock.json"

      - name: Checkout
        uses: actions/checkout@v3

      - name: Log in to the Container registry
        uses: docker/login-action@v2
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: |
            ${{ env.REGISTRY }}/${{ github.repository }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=sha
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=semver,pattern={{major}}

      - name: Build and push Docker image
        uses: docker/build-push-action@v4
        with:
          context: web
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
